package com.quartz1.service.impl;

import cn.hutool.core.lang.UUID;
import com.quartz1.dao.JobAndTriggerMapper;
import com.quartz1.model.JobAndTrigger;
import com.quartz1.model.JobInfo;
import com.quartz1.service.BaseJob;
import com.quartz1.service.ScheduleService;
import com.quartz1.tool.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

/**
 * Quartz定时任务操作实现类
 * Created by macro on 2020/9/27.
 */
@Slf4j
@Service
public class ScheduleServiceImpl implements ScheduleService {
    @Autowired
    private Scheduler scheduler;
    private String defaultGroup = "group1";

    @Autowired
    private JobAndTriggerMapper jobAndTriggerMapper;

    @Override
    public Boolean scheduleJob(JobInfo jobInfo) {
        boolean success = false;
        // 创建需要执行的任务
        JobDetail jobDetail = null;
        try {
            jobDetail = JobBuilder.newJob(getClass(jobInfo.getJobClassName()).getClass())
                    .withIdentity(jobInfo.getJobClassName(), jobInfo.getJobGroupName())
    //                .usingJobData("data", data)
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
        }
        //创建触发器，指定任务执行时间
        CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity(jobInfo.getJobClassName(), jobInfo.getJobGroupName())
                .withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCronExpression()))
                .build();
        //使用调度器进行任务调度
        try {
            scheduler.scheduleJob(jobDetail, cronTrigger);
            success = true;
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.info("创建定时任务失败！");
        } catch (Exception e) {
            e.printStackTrace();
            log.info("创建定时任务失败1！");
        }
        return success;
    }

    /**
     * 根据类名称，通过反射得到该类，然后创建一个BaseJob的实例。
     * 由于NewJob和HelloJob都实现了BaseJob，
     * 所以这里不需要我们手动去判断。这里涉及到了一些java多态调用的机制
     * 2019 12/24更新不再使用反射，使用SpringUtil工具类；
     * 前提是具体的Job类必须交给Spring来管理;
     * 例如：HelloJob 在其类上加上@Component("helloJob")注解，并指定传入Bean的名称；
     * @param classname
     * @return
     * @throws Exception
     */
    public BaseJob getClass(String classname) throws Exception {
        //Class<?> class1 = Class.forName(classname);
        //BaseJob baseJob = (BaseJob) class1.newInstance();
        BaseJob baseJob = (BaseJob) SpringUtil.getBean(classname);
        return baseJob;
    }

    @Override
    public String scheduleJob(Class<? extends Job> jobBeanClass, String cron, String data) {
        // 创建需要执行的任务:jobName不能写死，不然新增Job会失败，jobName也可以设置成动态输入
        String jobName = "printLogJob-"+UUID.fastUUID().toString();
//        String jobName = "printLogJob";
        //UUID(Universally Unique Identifier)全局唯一标识符,是指在一台机器上生成的数字，它保证对在同一时空中的所有机器都是唯一的，是由一个十六位的数字组成,表现出来的 形式。
        JobDetail jobDetail = JobBuilder.newJob(jobBeanClass)
                .withIdentity(jobName, defaultGroup)
                .usingJobData("data", data)
                .build();
        //创建触发器，指定任务执行时间
        CronTrigger cronTrigger = TriggerBuilder.newTrigger()
                .withIdentity(jobName, defaultGroup)
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();
        //使用调度器进行任务调度
        try {
            scheduler.scheduleJob(jobDetail, cronTrigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
            log.info("创建定时任务失败！");
        }
        return jobName;
    }

    @Override
    public Boolean reScheduleJob(String jobName, String jobGroup, String cronExpression) throws Exception{
        boolean success = false;
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
            // 表达式调度构建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            // 按新的cronExpression表达式重新构建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            // 按新的trigger重新设置job执行
            scheduler.rescheduleJob(triggerKey, trigger);
            success = true;
        } catch (SchedulerException e) {
            log.info("更新定时任务失败" + e);
            throw new Exception("更新定时任务失败");
        } catch (Exception e) {
            log.info("更新定时任务失败1" + e);
            throw new Exception("更新定时任务失败1");
        }
        return success;
    }

    @Override
    public Boolean pausejob(String jobName, String jobGroup) throws Exception {
        boolean success = false;
        try {
            scheduler.pauseJob(JobKey.jobKey(jobName, jobGroup));
            success = true;
        } catch (SchedulerException e) {
            log.info("暂停定时任务失败" + e);
            throw new Exception("暂停定时任务失败");
        } catch (Exception e) {
            log.info("暂停定时任务失败1" + e);
            throw new Exception("暂停定时任务失败1");
        }
        return success;
    }

    @Override
    public Boolean resumejob(String jobName, String jobGroup) throws Exception {
        boolean success = false;
        try {
            scheduler.resumeJob(JobKey.jobKey(jobName, jobGroup));
            success = true;
        } catch (SchedulerException e) {
            log.info("恢复定时任务失败" + e);
            throw new Exception("恢复定时任务失败");
        } catch (Exception e) {
            log.info("恢复定时任务失败1" + e);
            throw new Exception("恢复定时任务失败1");
        }
        return success;
    }

    @Override
    public Boolean cancelScheduleJob(String jobName) {
        boolean success = false;
        try {
            // 暂停触发器
            scheduler.pauseTrigger(new TriggerKey(jobName, defaultGroup));
            // 移除触发器中的任务
            scheduler.unscheduleJob(new TriggerKey(jobName, defaultGroup));
            // 删除任务
            scheduler.deleteJob(new JobKey(jobName, defaultGroup));
            success = true;
        } catch (SchedulerException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return success;
    }

    @Override
    public List<JobAndTrigger> getJobAndTriggerDetails(int pageNow, int pageSize){
        int pageNum = (pageNow-1)*pageSize;
        return jobAndTriggerMapper.getJobAndTriggerDetails(pageNum,pageSize);
    }
}
